﻿/*
 * modbustcpmaster.cpp
 *
 *  Created on: 2017年10月30日
 *      Author: work
 */

#include <dm/export.hpp>

#define DM_API_PROTOCOL DM_API_EXPORT

#include <dm/protocol/modbustcpmaster.hpp>
#include <dm/os/log/logger.hpp>

namespace dm{
namespace protocol{

static const char* logModule = "CModbusTcpMaster.protocol.dm";

CModbusTcpMaster::CModbusTcpMaster():CProtocol(),CModbusTcp(),m_transFlag(0),m_unitFlag(1){
	setWaitMaxTimes(3);
	setWaitTimeout(5);

	log().debug(THISMODULE "创建对象。默认等待时间%d 次数%d",m_waitTimeout,m_timeoutMaxTimes);
}

CModbusTcpMaster::~CModbusTcpMaster(){
	log().debug(THISMODULE "销毁对象");
}

CFrameModbusTcp* CModbusTcpMaster::genRxTempFrame(){
	CFrameModbusTcp* f = new CFrameModbusTcp;
	f->setUpFrame();
	return f;
}

CFrameModbusTcp* CModbusTcpMaster::genTxTempFrame(){
	CFrameModbusTcp* f = new CFrameModbusTcp;
	f->setDnFrame();
	return f;
}

void CModbusTcpMaster::reset( const ts_t& ts,const rts_t& rts ){
	CModbusTcp::reset(ts,rts);
	m_transFlag = 0;
}

CModbusTcpMaster::EAction CModbusTcpMaster::dealRxFrame( const ts_t& ts,const rts_t& rts ){
	noWait();

	if( rxFrame().getFunc()!=txFrame().getFunc() ){
		log().debug(THISMODULE "接收到的功能码%02X与发送%02X不一致",rxFrame().getFunc(),txFrame().getFunc());
		return Action_Nothing;
	}

	// 收发进行对比，接收到的应该和发送的相对应
	switch( rxFrame().getFunc() ){
	case CFrameModbusTcp::ReadCoilStatus:
		log().debug(THISMODULE "ReadCoilStatus");
		return dealRxResponse_readCoils( rxFrame(),txFrame(),ts,rts );

	case CFrameModbusTcp::ReadInputStatus:
		log().debug(THISMODULE "ReadInputStatus");
		return dealRxResponse_readDiscreteInputs( rxFrame(),txFrame(),ts,rts );

	case CFrameModbusTcp::ReadHoldReg:
		log().debug(THISMODULE "ReadHoldReg");
		return dealRxResponse_readHoldingRegisters(rxFrame(),txFrame(),ts,rts );

	case CFrameModbusTcp::ReadInputReg:
		log().debug(THISMODULE "ReadInputReg");
		return dealRxResponse_readInputRegisters(rxFrame(),txFrame(),ts,rts );

	case CFrameModbusTcp::ForceSigCoil:
		log().debug(THISMODULE "ForceSigCoil");
		return dealRxResponse_writeSingleCoil(rxFrame(),txFrame(),ts,rts );

	case CFrameModbusTcp::PresetSigReg:
		log().debug(THISMODULE "PresetSigReg");
		return dealRxResponse_writeSingleRegister(rxFrame(),txFrame(),ts,rts );

	case CFrameModbusTcp::ForceMtlCoil:
		log().debug(THISMODULE "ForceMtlCoil");
		return dealRxResponse_writeMultipleCoils( rxFrame(),txFrame(),ts,rts );

	case CFrameModbusTcp::PresetMtlReg:
		log().debug(THISMODULE "PresetMtlReg");
		return dealRxResponse_writeMultipleRegisters( rxFrame(),txFrame(),ts,rts );

	default:
		log().debug(THISMODULE "未支持功能码%02X",txFrame().getFunc());
		return Action_Nothing;
	}
}

/**
 * 开始召唤任务。
 * 这个函数被转交给专用规约处理函数。子类不应该再重载本函数。
 * @param txFrame
 * @return
 */
CModbusTcpMaster::EAction CModbusTcpMaster::taskStart_call( const ts_t& ts,const rts_t& rts ){
	EAction act = checkWait(rts);
	if( act!=Action_Nothing )
		return act;

	return setFrameTransflag(taskStart_call(txFrame(),ts,rts),txFrame());
}

/**
 * 执行召唤任务。
 * 这个函数被转交给规约专用处理函数。子类不应该再重载本函数。
 * @param txFrame
 * @return
 */
CModbusTcpMaster::EAction CModbusTcpMaster::taskDo_call( const ts_t& ts,const rts_t& rts ){
	EAction act = checkWait(rts);
	if( act!=Action_Nothing )
		return act;

	return setFrameTransflag(taskDo_call( txFrame(),ts,rts ),txFrame());
}

/**
 * 开始时钟同步任务。
 * 这个函数被转交给规约专用处理函数。子类不应该再重载本函数。
 * @param txFrame
 * @return
 */
CModbusTcpMaster::EAction CModbusTcpMaster::taskStart_syncClock( const ts_t& ts,const rts_t& rts ){
	EAction act = checkWait( rts );
	if( act!=Action_Nothing )
		return act;

	return setFrameTransflag(taskStart_syncClock( txFrame(),ts,rts ),txFrame());
}

/**
 * 执行时钟同步任务
 * 这个函数被转交给规约专用处理函数。子类不应该再重载本函数。
 * @param txFrame
 * @return
 */
CModbusTcpMaster::EAction CModbusTcpMaster::taskDo_syncClock( const ts_t& ts,const rts_t& rts ){
	EAction act = checkWait( rts );
	if( act!=Action_Nothing )
		return act;

	return setFrameTransflag(taskDo_syncClock( txFrame(),ts,rts ),txFrame());
}

/**
 * 开启远控任务
 * 这个函数被转交给规约专用处理函数。子类不应该再重载本函数。
 * @param txFrame
 * @return
 */
CModbusTcpMaster::EAction CModbusTcpMaster::taskStart_remoteControl( const ts_t& ts,const rts_t& rts ){
	EAction act = checkWait( rts );
	if( act!=Action_Nothing )
		return act;

	return setFrameTransflag(taskStart_remoteControl( txFrame(),ts,rts ),txFrame());
}

CModbusTcpMaster::EAction CModbusTcpMaster::taskDo_remoteControl( const ts_t& ts,const rts_t& rts ){
	EAction act = checkWait( rts );
	if( act!=Action_Nothing )
		return act;

	return setFrameTransflag(taskDo_remoteControl( txFrame(),ts,rts ),txFrame() );
}

CModbusTcpMaster::EAction CModbusTcpMaster::taskStart_parameters( const ts_t& ts,const rts_t& rts ){
	EAction act = checkWait( rts );
	if( act!=Action_Nothing )
		return act;

	return setFrameTransflag(taskStart_parameters( txFrame(),ts,rts ),txFrame() );
}

CModbusTcpMaster::EAction CModbusTcpMaster::taskDo_parameters( const ts_t& ts,const rts_t& rts ){
	EAction act = checkWait( rts );
	if( act!=Action_Nothing )
		return act;

	return setFrameTransflag(taskDo_parameters( txFrame(),ts,rts ),txFrame() );
}

/**
 * 开始召唤任务。
 * 默认处理函数设置启动标志，无其他操作。子类应该需要重载该函数。
 * @param
 * @return
 */
CModbusTcpMaster::EAction CModbusTcpMaster::taskStart_call( CFrameModbusTcp&,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	log().debug(THISMODULE "默认无操作");
	m_taskCall = Started;
	return Action_Nothing;
}

/**
 * 执行召唤任务
 * 默认处理函数设置召唤成功标志，无其他操作。
 * @param
 * @return
 */
CModbusTcpMaster::EAction CModbusTcpMaster::taskDo_call( CFrameModbusTcp&,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	log().debug(THISMODULE "默认无操作");
	m_taskCall = Success;
	return Action_Nothing;
}

/**
 * 开启时钟同步任务
 * 默认处理函数设置开始标志，无其他操作。
 * 一般子类应该设置对时报文，并设置启动标志。
 * @param
 * @return
 */
CModbusTcpMaster::EAction CModbusTcpMaster::taskStart_syncClock( CFrameModbusTcp&,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	log().debug(THISMODULE "默认无操作");
	m_taskClock = Started;
	return Action_Nothing;
}

CModbusTcpMaster::EAction CModbusTcpMaster::taskDo_syncClock( CFrameModbusTcp&,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	log().debug(THISMODULE "默认无操作");
	m_taskClock = Success;
	return Action_Nothing;
}

CModbusTcpMaster::EAction CModbusTcpMaster::taskStart_remoteControl( CFrameModbusTcp&,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	log().debug(THISMODULE "默认无操作");
	m_taskRmtCtl = Started;
	return Action_Nothing;
}

CModbusTcpMaster::EAction CModbusTcpMaster::taskDo_remoteControl( CFrameModbusTcp&,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	log().debug(THISMODULE "默认无操作");
	m_taskRmtCtl = Success;
	return Action_Nothing;
}

CModbusTcpMaster::EAction CModbusTcpMaster::taskStart_parameters( CFrameModbusTcp&,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	log().debug(THISMODULE "默认无操作");
	m_taskParas = Started;
	return Action_Nothing;
}

CModbusTcpMaster::EAction CModbusTcpMaster::taskDo_parameters( CFrameModbusTcp&,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	log().debug(THISMODULE "默认无操作");
	m_taskParas = Success;
	return Action_Nothing;
}

CModbusTcpMaster::EAction CModbusTcpMaster::dealRxResponse_readCoils( const CFrameModbusTcp& rf,CFrameModbusTcp& tf,const ts_t& ts,const rts_t& rts ){
	dm::uint16 startAddr = tf.getData_uint16(0);
	dm::uint16 quantity = tf.getData_uint16(2);

	if( rf.isErrorUpFrame() ){
		CFrameModbusTcp::EErrCode errCode;
		rf.getError(errCode);

		log().info(THISMODULE "收到错误帧:%02X",errCode);
		for( dm::uint16 i=0;i<quantity;++i ){
			coils_01_error( startAddr+i,errCode,ts,rts );
		}
	}else{
		if( rf.getData_uint8()!=tf.getBytes(quantity) ){
			log().warnning(THISMODULE "收到数据字节数%d 与请求数量%d->%d不匹配",rf.getData_uint8(),quantity,tf.getBytes(quantity));
			return Action_Nothing;
		}

		for( dm::uint16 i=0;i<quantity;++i )
			coils_01( startAddr+i,rf.getData_bit(i,1)?0x01:0x00,ts,rts);
	}

	return timedRefresh(ts,rts);
}

CModbusTcpMaster::EAction CModbusTcpMaster::dealRxResponse_readDiscreteInputs( const CFrameModbusTcp& rf,CFrameModbusTcp& tf,const ts_t& ts,const rts_t& rts ){
	dm::uint16 startAddr = tf.getData_uint16(0);
	dm::uint16 quantity = tf.getData_uint16(2);

	if( rf.isErrorUpFrame() ){
		CFrameModbusTcp::EErrCode errCode;
		rf.getError(errCode);
		log().info(THISMODULE "收到错误帧:%02X",errCode);
		for( dm::uint16 i=0;i<quantity;++i ){
			discreteInputs_02_error( startAddr+i,errCode,ts,rts );
		}
	}else{
		if( rf.getData_uint8()!=tf.getBytes(quantity) ){
			log().warnning(THISMODULE "收到数据字节数%d 与请求数量%d->%d不匹配",rf.getData_uint8(),quantity,tf.getBytes(quantity));
			return Action_Nothing;
		}

		for( dm::uint16 i=0;i<quantity;++i )
			discreteInputs_02( startAddr+i,rf.getData_bit(i,1),ts,rts);
	}

	return timedRefresh(ts,rts);
}

CModbusTcpMaster::EAction CModbusTcpMaster::dealRxResponse_readHoldingRegisters( const CFrameModbusTcp& rf,CFrameModbusTcp& tf,const ts_t& ts,const rts_t& rts ){
	dm::uint16 startAddr = tf.getData_uint16(0);
	dm::uint16 quantity = tf.getData_uint16(2);

	if( rf.isErrorUpFrame() ){
		CFrameModbusTcp::EErrCode errCode;
		rf.getError(errCode);
		log().info(THISMODULE "收到错误帧:%02X",errCode);
		for( dm::uint16 i=0;i<quantity;++i ){
			holdingRegisters_03_error( startAddr+i,errCode,ts,rts );
		}
	}else{
		if( rf.getData_uint8()!=(quantity*2) ){
			log().warnning(THISMODULE "收到数据字节数%d 与请求数量%d->%d不匹配",rf.getData_uint8(),quantity,quantity*2);
			return Action_Nothing;
		}

		for( dm::uint16 i=0;i<quantity;++i )
			holdingRegisters_03( startAddr+i,rf.getData_uint16(1+i*2),ts,rts );
	}

	return timedRefresh(ts,rts);
}

CModbusTcpMaster::EAction CModbusTcpMaster::dealRxResponse_readInputRegisters( const CFrameModbusTcp& rf,CFrameModbusTcp& tf,const ts_t& ts,const rts_t& rts ){
	dm::uint16 startAddr = tf.getData_uint16(0);
	dm::uint16 quantity = tf.getData_uint16(2);

	if( rf.isErrorUpFrame() ){
		CFrameModbusTcp::EErrCode errCode;
		rf.getError(errCode);
		log().info(THISMODULE "收到错误帧:%02X",errCode);
		for( dm::uint16 i=0;i<quantity;++i ){
			inputRegisters_04_error( startAddr+i,errCode,ts,rts );
		}
	}else{
		if( rf.getData_uint8()!=(quantity*2) ){
			log().warnning(THISMODULE "收到数据字节数%d 与请求数量%d->%d不匹配",rf.getData_uint8(),quantity,quantity*2);
			return Action_Nothing;
		}

		for( dm::uint16 i=0;i<quantity;++i )
			inputRegisters_04( startAddr+i,rf.getData_uint16(1+i*2),ts,rts);
	}

	return timedRefresh(ts,rts);
}

CModbusTcpMaster::EAction CModbusTcpMaster::dealRxResponse_writeSingleCoil( const CFrameModbusTcp& rf,CFrameModbusTcp& /*tf*/,const ts_t& ts,const rts_t& rts ){
	if( rf.isErrorUpFrame() ){
		log().info(THISMODULE "收到错误帧");
	}

	return timedRefresh(ts,rts);
}

CModbusTcpMaster::EAction CModbusTcpMaster::dealRxResponse_writeSingleRegister( const CFrameModbusTcp& rf,CFrameModbusTcp& /*tf*/,const ts_t& ts,const rts_t& rts ){
	if( rf.isErrorUpFrame() ){
		log().info(THISMODULE "收到错误帧");
	}

	return timedRefresh(ts,rts);
}

CModbusTcpMaster::EAction CModbusTcpMaster::dealRxResponse_writeMultipleCoils( const CFrameModbusTcp& rf,CFrameModbusTcp& /*tf*/,const ts_t& ts,const rts_t& rts ){
	if( rf.isErrorUpFrame() ){
		log().info(THISMODULE "收到错误帧");
	}

	return timedRefresh(ts,rts);
}

CModbusTcpMaster::EAction CModbusTcpMaster::dealRxResponse_writeMultipleRegisters( const CFrameModbusTcp& rf,CFrameModbusTcp& /*tf*/,const ts_t& ts,const rts_t& rts ){
	if( rf.isErrorUpFrame() ){
		log().info(THISMODULE "收到错误帧");
	}

	return timedRefresh(ts,rts);
}

void CModbusTcpMaster::coils_01_error( const dm::uint16& address,const CFrameModbusTcp::EErrCode& ec,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	log().info(THISMODULE "默认无处理。地址：%d,失败原因%d",address,ec);
}

/**
 * 处理返回的数据
 * 子类应该重载该函数
 * @param address
 * @param value
 */
void CModbusTcpMaster::coils_01( const dm::uint16& address,const dm::uint8& value,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	log().info(THISMODULE "默认无处理。地址：%d,值:%d",address,value);
}

void CModbusTcpMaster::discreteInputs_02_error( const dm::uint16& address,const CFrameModbusTcp::EErrCode& ec,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	log().info(THISMODULE "默认无处理。地址：%d,失败原因%d",address,ec);
}

/**
 * 处理返回的数据
 * 子类应该重载该函数
 * @param address
 * @param value
 */
void CModbusTcpMaster::discreteInputs_02( const dm::uint16& address,const dm::uint8& value,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	log().info(THISMODULE "默认无处理。地址：%d,值:%d",address,value);
}

void CModbusTcpMaster::holdingRegisters_03_error( const dm::uint16& address,const CFrameModbusTcp::EErrCode& ec,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	log().info(THISMODULE "默认无处理。地址：%d,失败原因%d",address,ec);
}

/**
 * 处理返回的数据
 * 子类应该重载该函数
 * @param address
 * @param value
 */
void CModbusTcpMaster::holdingRegisters_03( const dm::uint16& address,const dm::uint16& value,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	log().info(THISMODULE "默认无处理。地址：%d,值:%d",address,value);
}

void CModbusTcpMaster::inputRegisters_04_error( const dm::uint16& address,const CFrameModbusTcp::EErrCode& ec,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	log().info(THISMODULE "默认无处理。地址：%d,失败原因%d",address,ec);
}

/**
 * 处理返回的数据
 * 子类应该重载该函数
 * @param address
 * @param value
 */
void CModbusTcpMaster::inputRegisters_04( const dm::uint16& address,const dm::uint16& value,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	log().info(THISMODULE "默认无处理。地址：%d,值:%d",address,value);
}

CModbusTcpMaster::EAction CModbusTcpMaster::setFrameTransflag( const CModbusTcpMaster::EAction& act,CFrameModbusTcp& tf ){
	if( act==Action_Send || act==Action_SendAndReTime ){
		++m_transFlag;
		tf.setTransFlag(m_transFlag);
	}

	tf.setUnitFlag(m_unitFlag);
	return act;
}

}
}


